package com.wzy.portfolio.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.StringUtils;
import com.wzy.portfolio.component.StockMonitorCpt;
import com.wzy.portfolio.mapper.StockMapper;
import com.wzy.portfolio.model.*;
import com.wzy.portfolio.service.StockService;
import com.wzy.portfolio.utils.NumChangeUtil;
import com.wzy.portfolio.utils.RedisUtil;
import com.wzy.portfolio.utils.StockUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class StockServiceImpl implements StockService {

    @Resource
    StockMapper stockMapper;

    @Autowired
    StockMonitorCpt stockMonitorCpt;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void stockMonitor() {
        List<StockMonitorDto> list = stockMapper.getStockMonitor();
        for (StockMonitorDto dto : list) {
            try {
                StockPriceDto priceDto = StockUtil.stockPrice(dto.getStockCode());
                Integer num = dto.getNum();
                double currentPrice = priceDto.getCurrentPrice();//实时价
                double yestedayPrice = priceDto.getYestedayPrice();//昨日收盘价
                dto.setCurrentPrice(currentPrice);
                dto.setChangePct(priceDto.getChangePct());
                if(num != null&&dto.getCostPrice()!=null){
                    dto.setRealEarnings( (currentPrice - yestedayPrice) * dto.getNum());//实时收益
                    dto.setPositionEarnings((currentPrice - dto.getCostPrice()) * dto.getNum());//持仓收益
                    dto.setAvgPrice5(priceDto.getAvgPrice5());
                    dto.setAvgPrice10(priceDto.getAvgPrice10());
                    dto.setAvgPrice30(priceDto.getAvgPrice30());
                }
                stockMonitorCpt.parseStockMonitor(dto,priceDto);//开始分析数据
                stockMapper.updateStockMonitor(dto);
            }catch (Exception e){
                 log.error("股票({}),查询价格并分析数据异常:{}", dto.getStockName(), e.getMessage(), e);
            }
        }
    }

    /**
     * 更新股票最高最低最新价
     */
    @Override
    public void updateStockMaxNewPrice() {
        List<StockBaseDto> stockList = stockMapper.getAllStock();
        for(int m = 0 ; m < stockList.size(); m++){
            StockBaseDto base = stockList.get(m);
            StockBaseDto dto = stockMapper.stockMaxNewPrice(base.getStockCode());
            if(dto!=null){
                stockMapper.updateStockMaxNewPrice(dto);
                log.info("股票:{},最高价:{},最低价:{},最新价:{},回撤:{}", base.getStockName(), dto.getMaxPrice(), dto.getMinPrice(), dto.getNewPrice(), dto.getRate());
            }
        }
    }

    /**
     * 获取财报信息
     */
    @Override
    public void reportInfo(String reportDate) {
        List<StockBaseDto> list = stockMapper.getNoReportStock(reportDate);
        log.info("本次待更新财报信息的股票数量为:{}条", list.size());
        for (StockBaseDto dto : list) {
            try {
                byte[] excelBytes = HttpUtil.downloadBytes("https://basic.10jqka.com.cn/api/stock/export.php?export=main&type=report&code=" + dto.getStockCode());
                ExcelReader reader = ExcelUtil.getReader(new ByteArrayInputStream(excelBytes), 0);
                int rowCount = reader.getRowCount();
                for (int rowIndex = 1; rowIndex < rowCount; rowIndex++) {// 从第2行开始遍历（跳过表头后的第一行）
                    List<Object> excelList = reader.readRow(rowIndex);  // 读取当前行数据（转换为Map）
                    String content = JSON.toJSONString(excelList);
                    if (content.contains("科目")) {
                        dto.setReportDate(excelList.get(1) + "");
                    }
                    if (content.contains("净利润(元)")) {
                        BigDecimal attributableToParent = new BigDecimal(excelList.get(1) + "");
                        dto.setReportStatus(Double.parseDouble(excelList.get(1) + "")>0?"盈利":"亏损");
                        dto.setAttributableToParent(NumChangeUtil.convertToYiOrWan(attributableToParent));
                    }
                    if (content.contains("净利润同比增长率")) {
                        dto.setAttributableToParentRate(excelList.get(1) + "");
                    }
                    if (content.contains("营业总收入(元)")) {
                        dto.setTotalOperatingRevenue(NumChangeUtil.convertToYiOrWan(new BigDecimal(excelList.get(1) + "")));
                    }
                    if (content.contains("营业总收入同比增长率")) {
                        dto.setTotalOperatingRevenueRate(excelList.get(1) + "");
                        log.info("解析完毕:{}", dto);
                        stockMapper.updateStockReportInfo(dto);
                        break;
                    }
                }
            }catch (Exception e){
                log.error("股票:{},获取财报信息异常:{}", dto.getStockName(), e.getMessage());
            }
        }
    }

    /**
     * 股票历史数据入库
     */
    @Override
    public void historyPriceQueue() {
        String redisKey = "STOCK:BASE:QUEUE";
        StockBaseDto baseDto = redisUtil.leftPop(redisKey);// 从队列左侧弹出元素（消费并删除）
        if (baseDto == null) {
            log.info("--->东财网队列中无待消费的数据--->");
            return;
        }
        Long tmpSize = redisUtil.hasValueInQueue(redisKey);
        log.info("队列中还剩:{}条,本次消费:{}", (tmpSize-1), baseDto.getStockName());
        String cookie = redisUtil.get("DFCF:COOKIE")+"";
        List<StockPriceDto> stockPriceList = StockUtil.eastMoneyApi(baseDto,cookie);//东财网络接口数据
        if(stockPriceList==null){
            log.error("股票:{},从东财网获取数据失败,重新写入Redis队列中", baseDto.getStockName());
            redisUtil.pushQueueOne(redisKey,baseDto);
        } else if(stockPriceList.isEmpty()){
            log.info("股票:{}({}) 无历史数据", baseDto.getStockName(), baseDto.getStockCode());
        }else {
            stockMapper.addStockHistoryPrice(stockPriceList);
        }
    }

    /**
     * 东财网股票历史数据入队列
     *
     * @param req
     */
    @Override
    public String dcwHistoryPrice(StockHistoryReq req) {
        String redisKey = "STOCK:BASE:QUEUE";
        Long size = redisUtil.hasValueInQueue(redisKey);
        if (size == null || size == 0) {
            log.info("--->redis队列中无数据,准备重数据库加载<---");
            List<StockBaseDto> list = stockMapper.getAllStock();
            redisUtil.pushQueue(redisKey,req,list);
            return "本次写入队列:"+list.size()+"条数据";
        }else {
            return "队列中还有:"+size+"条数据等待消费";
        }
    }

    /**
     * 股票当日数据入库
     */
    @Override
    public void stockDayData() {
        List<StockBaseDto> list = stockMapper.getAllStock();
        for (StockBaseDto dto : list) {
            String type = StringUtils.isNoneBlank(dto.getType()) ? dto.getType() : "sh";
            try {
                StockPriceDto priceDto = StockUtil.stockPrice(type + dto.getStockCode());
                List<StockPriceDto> tmpList = new ArrayList<>();
                tmpList.add(priceDto);
                stockMapper.addStockHistoryPrice(tmpList);
                if(priceDto.getChangePct()>8.8){//实时涨跌幅大于8.8,写入监控表,监控是否单阳不破
                    StockPriceDto historyPrice = stockMapper.getHistoryPrice(dto.getStockCode());
                    //1:昨日涨幅小于5个点  2:当日交易量对比上个交易日放倍量
                    if(historyPrice!=null&&historyPrice.getChangePct()<5 && historyPrice.getVolume()>0.5 && priceDto.getVolume()> historyPrice.getVolume()*3){
                        StockMonitorDto monitorDto = new StockMonitorDto();
                        BeanUtils.copyProperties(priceDto, monitorDto);
                        monitorDto.setMonitorType("单阳不破");
                        monitorDto.setRemark("单阳不破,放倍量("+historyPrice.getVolume()+"-->"+priceDto.getVolume()+"),回调开盘价("+priceDto.getOpenPrice()+")可博弈");
                        monitorDto.setMonitorMinPrice(priceDto.getOpenPrice());
                        monitorDto.setMonitorMaxPrice(priceDto.getCurrentPrice()*(1+0.02));
                        monitorDto.setMonitorStatus(1);
                        stockMapper.addStockMonitor(monitorDto);
                    }
                }
            }catch (Exception e){
                log.error("{}:当日行情数据查询失败:{}", dto.getStockName(), e.getMessage(), e);
            }
        }
    }
}
